package org.viettan.android.main.io;

import java.lang.ref.WeakReference;

import org.viettan.android.main.managers.DialogManager;
import org.viettan.android.main.model.Entity;

import android.app.Activity;
import android.os.AsyncTask;

/**
 * The {@code DownloadEntityTask} is an abstraction over Android's {@link AsyncTask} for the purpose
 * of downloading any kind of {@link Entity} from Viet Tan's website on a background thread, and
 * displaying the usual "Please wait" dialog while doing so. If the download succeeds, the results
 * will be passed to the {@link #displayEntity(Object)} method. If the download fails, a general
 * error message will be displayed to the user.
 * 
 * @param <A>
 *            the activity to get keep a {@link WeakReference} on.
 * @param <T>
 *            the type of object to be downloaded
 */
public abstract class DownloadEntityTask<A extends Activity, T> extends AsyncTask<Void, Void, T> {

    // please read http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
    // as to why we need a WeakReference

    private static final int MAX_RETRIES = 3;
    private final Logger logger = new Logger();
    private final DialogManager notificationManager;
    private final WeakReference<A> activity;

    public DownloadEntityTask(A activity, DialogManager notificationManager) {
	this.notificationManager = notificationManager;
	this.activity = new WeakReference<A>(activity);
    }

    @Override
    protected void onPreExecute() {
	notificationManager.startProgress();
    }

    @Override
    protected T doInBackground(Void... ignored) {
	int trials = 1;
	do {
	    try {
		return getEntity();
	    } catch (EntityRetrievalException e) {
		logger.severe("Unable to download on " + trials + ". trial: " + e);
	    }
	} while (trials++ < MAX_RETRIES);
	return null;
    }

    @Override
    protected void onPostExecute(T articles) {
	notificationManager.endProgress();
	if (articles == null) {
	    notificationManager.showEntityRetrievalError(null);
	} else {
	    displayEntity(articles);
	}
    }

    protected A getActivity() {
	return activity.get();
    }

    protected abstract T getEntity() throws EntityRetrievalException;

    protected abstract void displayEntity(T results);
}
